package mongodb

import (
	"context"
	"fmt"
	"strconv"
	"time"

	"github.com/docker/go-connections/nat"

	"github.com/testcontainers/testcontainers-go"
	"github.com/testcontainers/testcontainers-go/wait"
)

type (
	Container struct {
		testcontainers.Container

		username string
		password string
		host     string
	}
)

const (
	usernameVariable   = "MONGO_INITDB_ROOT_USERNAME"
	passwordVariable   = "MONGO_INITDB_ROOT_PASSWORD"
	defaultMongoDBPort = 27017
	defaultTimeout     = 5 * time.Minute
)

func StartContainer(ctx context.Context) *Container {
	username := "user"
	password := "password"

	environments := map[string]string{}
	environments[usernameVariable] = username
	environments[passwordVariable] = password

	port, err := nat.NewPort("", strconv.Itoa(defaultMongoDBPort))
	if err != nil {
		panic(err)
	}

	request := testcontainers.ContainerRequest{
		Image:        "mongo:4.4.8",
		Env:          environments,
		ExposedPorts: []string{string(port)},
		WaitingFor:   wait.ForLog("Waiting for connections").WithStartupTimeout(defaultTimeout),
	}

	container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
		ContainerRequest: request,
		Started:          true,
	})
	if err != nil {
		panic(err)
	}

	host, err := container.Host(ctx)
	if err != nil {
		panic(err)
	}

	mappedPort, err := container.MappedPort(ctx, port)
	if err != nil {
		panic(err)
	}

	return &Container{
		Container: container,
		username:  username,
		password:  password,
		host:      fmt.Sprintf("%s:%d", host, mappedPort.Int()),
	}
}

func (c *Container) ConnectionURI() string {
	return fmt.Sprintf("mongodb://%s:%s@%s/?connect=direct", c.username, c.password, c.host)
}
